import {decodeBase64, encodeBase64, fetch} from './util'

export default class API {
	constructor(options){
		this.appinfo = {
			app_id: options.appid,
			app_key: options.appkey
		}
		this.server = {
            appid: options.appid,
            appkey: options.appkey,
            host: options.host,
            baseUrl: options.host + '/api/api.php'
        }
	}
	time = () => {
		return parseInt((new Date).getTime()/1000);
	}

	applyFetch(mod, method = 'POST'){
        return (data) => {
            let url = this.server.baseUrl + '?mod=' + mod
            const options = {
                method: method,
                headers: {
                    'Content-Type': 'application/json;'
                }
            }
            if(method === 'POST'){
                options.body = JSON.stringify(data)
            } else if(method === 'GET'){
                Object.keys(data).forEach(i => {
                    url += `&${i}=${data[i]}`
                })
            }
            return fetch(url, options).then(res => {
            	return res.text().then(text => {
            		try{
    	        		return JSON.parse(text)
            		} catch(e) {
            			return text;
            		}
            	})
            	
            })
        }
    }
    signature = this.applyFetch('signature')

    // sign and verify sign
    signVerify(data, str){
        const param = {
            act: 'verify',
            signature: str,
            ...data
        }
        return this.signature(param).then(res => {
            if(res && res.rcode === 'y050403'){
                return str;
            } else {
                throw new Error("signature verify fail!")
            }
        })
    }

    sign(data){
    	const json = data;
    	let __signature;
    	const reqData = {
    		...this.appinfo,
            ...this.appinfo,
    		time: this.time(),
    		params: json
    	}
    	return this.signature({
    		...reqData,
    		act: 'signature'
    	})
		.then(res => {
			if(res && res.rcode === 'y050404'){
				__signature = res.signature
				return res.signature
			} else {
				throw new Error('signature fail!')
			}
		})
		.then(signature => {
            return this.signVerify(reqData, signature)
		})
		
    }

    genCommonMod(mod, method = "POST"){
        return async data => {
            const param = {
                ...data,
                ...this.appinfo,
                time: this.time()
            }
            param.signature = await this.sign(param);
            const res = await this.applyFetch(mod, method)(param)
            return res
        }
    }
    code = this.genCommonMod('code')
    encode(data){
        const decodeData = {}
        Object.keys(data).forEach(i => {
            decodeData[i] = encodeBase64(data[i])
        })
        return this.code({
            act: 'encode',
            data: JSON.stringify(decodeData)
        })
        .then(res => {
            if(res.rcode === 'y050405'){
                return res.code
            } else {
                throw new Error("encode error!")
            }
        })
    }
    decode(code){
        return this.code({
            act: 'decode',
            code
        })
        .then(res => {
            const real = {}
            Object.keys(res).forEach(i => {
                real[i] = decodeBase64(res[i])
            })
            return real
        })
    }

    genFeatureMod(mod, method = "POST"){
        const inst = this.genCommonMod(mod, method);
        return data => inst(data)
            .then(res => {
                if(res && ~res.rcode.indexOf('y')){
                    return res.code
                } else {
                    throw new Error(res ? res.msg : 'unknow error!')
                }
            })
            .then(code => this.decode(code))
    }
}